package com.jtw.sys.controller.member;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jtw.common.anno.RequestAnno.PermAnno;
import com.jtw.common.bean.Result.Message;
import com.jtw.common.bean.enums.FilePathEnums;
import com.jtw.common.bean.enums.PermGroup;
import com.jtw.common.bean.enums.ReqCode;
import com.jtw.common.bean.vo.FindPagingVo;
import com.jtw.common.org.Sid;
import com.jtw.common.token.ClientToken;
import com.jtw.common.util.*;
import com.jtw.common.weixin.shareUtil;
import com.jtw.conf.shiro.CustomTypeToken;
import com.jtw.conf.shiro.enums.LoginType;
import com.jtw.conf.shiro.model.BaseUser;
import com.jtw.sys.constants.Constant;
import com.jtw.sys.model.user.TSysUserInfo;
import com.jtw.sys.service.information.SysInformationServiceImpl;
import com.jtw.sys.service.log.SysLoginServiceImpl;
import com.jtw.sys.service.member.MemberAssetServiceImpl;
import com.jtw.sys.service.perm.AuthService;
import com.jtw.sys.service.user.SysUserServiceImpl;
import com.jtw.sys.vo.member.MemberUserInfoModifyReq;
import com.jtw.sys.vo.user.SysUserAddReq;
import com.jtw.sys.vo.user.SysUserInfoBaseVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.subject.Subject;
import org.apache.tika.exception.TikaException;
import org.joda.time.LocalDateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
//import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.xml.sax.SAXException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.*;


@Api(tags = "系统会员管理模块")
@RestController
@Slf4j
@Validated //开启访问参数校验
@RequestMapping(value = "/sys/member")
public class SysMemberController {

    @Autowired
    private Sid sid;
    @Autowired
    private AuthService authService;
    @Autowired
    private SysUserServiceImpl sysUserServiceImpl;
    @Autowired
    private MemberAssetServiceImpl memberAssetServiceImpl;
    @Autowired
    SysInformationServiceImpl sysInformationServiceImpl;
    @Autowired
    private SysLoginServiceImpl sysLoginService;

    @Value("${fileSaveDirectory}")
    private  String fileSaveDirectory;

    @Value("${fileSavePath}")
    private  String fileSavePath;
//    @Autowired
//    private RedisTemplate redisTemplate;


    @ApiOperation(notes = "公开权限组", value = "会员登陆入口")
    @ApiImplicitParams({@ApiImplicitParam(name = "userName", value = "账号", required = true, dataType = "String", paramType = "form"),
            @ApiImplicitParam(name = "password", value = "密码", required = true, dataType = "String", paramType = "form"),
            @ApiImplicitParam(name = Constant.KEY_CAPTCHA, value = "验证码", required = true, dataType = "String", paramType = "form")})
    @Transactional
    @PostMapping(value = "/login")
    @PermAnno(sort = 1, group = 1, open = true)
    public Message login(@RequestParam @NotBlank(message = "用户名不能为空") String userName,
                         @RequestParam @NotBlank(message = "密码不能为空") String password,
//                         @RequestParam @NotBlank(message = "验证码不能为空") String rand,
                         HttpSession httpsession,
                         HttpServletRequest request
    ) {
//        Object rand1 = httpsession.getAttribute(Constant.KEY_CAPTCHA);
//        if (rand1 == null) {
//            return ReqCode.IndentifyCodeMissing.getMessage();
//        }
//        if (!rand.toUpperCase().equals(rand1.toString())) {
//            return ReqCode.IndentifyCodeError.getMessage();
//        }
        CustomTypeToken customTypeToken = new CustomTypeToken(userName,password);//密码登陆
//        CustomTypeToken usernamePasswordToken = new CustomTypeToken("WEQWEQW","",LoginType.WXGZH,false,"");//免密登陆
//        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(userName, password);
        Subject subject = SecurityUtils.getSubject();
        //检测用户登陆信息
        try {
//            customTypeToken.setRememberMe(true);
            subject.login(customTypeToken);
        } catch (IncorrectCredentialsException ice) {
            // 密码错误异常
            throw ReqCode.SysLoginPasswordError.getException();
        } catch (UnknownAccountException uae) {
            // 未知用户名异常
            throw ReqCode.SysLoginUnKnowAccount.getException();
        } catch (ExcessiveAttemptsException eae) {
            // 错误登录过多的异常
            throw ReqCode.SysLoginExcessiveAttempts.getException();
        } catch (LockedAccountException lae) {
            //账号锁定异常
            throw ReqCode.SysLoginLockedAccount.getException();
        }
//        开启redis session管理的化 需要激活次方法 限制同一账号多端登陆
//        Object sessionid = redisTemplate.opsForValue().get(userName);
//        if(sessionid!=null){
//            //如果有 则前面的session失效；
//            redisTemplate.delete(Constant.KEY_SPRING_SESSION_PREFFIX+sessionid.toString());
//            redisTemplate.expire(Constant.KEY_SPRING_SESSION_EXPIRES_PREFFIX+sessionid.toString(),0,TimeUnit.SECONDS);
//        }
//        redisTemplate.opsForValue().set(userName,subject.getSession().getId(),3600,TimeUnit.SECONDS);


        //登录成功之后删除rand
        httpsession.removeAttribute(Constant.KEY_CAPTCHA);
        //创建客户端的用户信息token
        ClientToken clientToken = new ClientToken();
        SysUserInfoBaseVo sysUserInfoBaseVo = sysUserServiceImpl.getUserInfoBaseVoByUserName(userName);
        //更新登陆时间
        sysUserServiceImpl.updateUserLoginTime(sysUserInfoBaseVo.getId());
        //登陆成功之后自动签到

        //生成跨域token
        String csrfToken = UUID.randomUUID().toString().replace("-", "");
        subject.getSession().setAttribute(Constant.KEY_USER_INFO, sysUserInfoBaseVo); //存储基本信息
        subject.getSession().setAttribute(Constant.KEY_USER_USER_NAME, userName); //存储基本信息
        subject.getSession().setAttribute(Constant.USER_PRIMARY_KEY, sysUserInfoBaseVo.getId());
        subject.getSession().setAttribute(Constant.KEY_CSRF_TOKEN, csrfToken);

        //插入登陆记录
        sysLoginService.saveLoinLog(request,sysUserInfoBaseVo.getId(),1);
        //生成签到记录
        Integer todayCheckIn = sysUserServiceImpl.getTodayCheckIn(sysUserInfoBaseVo.getId());
        if(todayCheckIn.intValue()==0){
            sysUserServiceImpl.memberCheckIn(sysUserInfoBaseVo.getId());
        }
        //生成登陆成功的返回信息
        Map<String, String> map = new HashMap<String, String>();
        map.put(Constant.KEY_CLIENT_TOKEN, ClientToken.createClientToken(clientToken));
        map.put(Constant.KEY_CSRF_TOKEN, csrfToken);
        return ReqCode.Success.getMessage(map);
    }

    @ApiOperation(notes = "公开权限组", value = "会员注册入口")
    @ApiImplicitParams({@ApiImplicitParam(name = "userName", value = "账号", required = true, dataType = "String", paramType = "form"),
            @ApiImplicitParam(name = "password", value = "密码", required = true, dataType = "String", paramType = "form"),
            @ApiImplicitParam(name = Constant.KEY_CAPTCHA, value = "验证码", required = true, dataType = "String", paramType = "form"),
            @ApiImplicitParam(name = "nickName", value = "昵称", required = true, dataType = "String", paramType = "form")})
    @PostMapping(value = "/sign")
    @PermAnno(sort = 1, group = 1, open = true)
    public Message sign(@RequestParam @NotBlank(message = "用户名不能为空") String userName,
                        @RequestParam @NotBlank(message = "登陆密码不能为空") String password,
                        @RequestParam @NotBlank(message = "验证码不能为空") String rand,
                        String inviteCode,
                        @RequestParam @NotBlank(message = "昵称不能为空")String nickName,
                        HttpSession httpsession,
                        HttpServletRequest request
    ) {
        Object rand1 = httpsession.getAttribute(Constant.KEY_CAPTCHA);
        if (rand1 == null) {
            return ReqCode.IndentifyCodeMissing.getMessage();
        }
        if (!rand.toUpperCase().equals(rand1.toString())) {
            return ReqCode.IndentifyCodeError.getMessage();
        }

        if(!Validator.isMobile(userName)||userName.length()>20){
            return ReqCode.isNotTrueAccountFormat.getMessage();
        }

        SysUserAddReq sysUserAddReq = new SysUserAddReq();
        sysUserAddReq.setUserName(userName);
        sysUserAddReq.setNickName(nickName);
        sysUserAddReq.setPassword(password);
        sysUserAddReq.setInviteCode(inviteCode);
        sysUserServiceImpl.addSysUserAccount(sysUserAddReq,request);
        return ReqCode.SignUpSuccess.getMessage();
    }

    @ApiOperation(notes = "会员登陆可用组", value = "获取当前会员的基本信息")
    @GetMapping("/getMemberUserBaseInfoVo")
    @PermAnno(sort = 2, group = 98)
    public Message getSysUserBaseInfoVo() {

        Long userId = (Long) SecurityUtils.getSubject().getSession().getAttribute(Constant.USER_PRIMARY_KEY);

        SysUserInfoBaseVo sysUserInfoBaseVo = sysUserServiceImpl.getUserInfoBaseVoByUserId(userId);

        SecurityUtils.getSubject().getSession().setAttribute(Constant.KEY_USER_INFO, sysUserInfoBaseVo);
        ObjectMapper objectMapper = new ObjectMapper();
        String user=null;
        try {
            user = Base64.getEncoder().encodeToString(objectMapper.writeValueAsString(sysUserInfoBaseVo).getBytes("UTF-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return ReqCode.SelectSuccess.getMessage(user);
    }

    @ApiOperation(notes = "会员登陆可用组", value = "会员退出登录")
    @PostMapping("/logout")
    @PermAnno(sort = 1, group = 98)
    public Message logout() {
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        subject.getSession().removeAttribute(Constant.KEY_USER_INFO);
        return ReqCode.Success.getMessage();
    }

    @ApiOperation(notes = "会员登陆可用组", value = "会员修改基本信息")
    @PostMapping("/modifyMemberUserBaseInfo")
    @PermAnno(sort = 19, group = 98)
    public Message modifyMemberUserBaseInfo(HttpServletRequest request,@Valid MemberUserInfoModifyReq memberUserInfoModifyReq) {
        TSysUserInfo sysUserInfo = new TSysUserInfo();
        BeanUtils.copyProperties(memberUserInfoModifyReq, sysUserInfo);
        sysUserInfo.setId((Long) request.getSession().getAttribute(Constant.USER_PRIMARY_KEY));
        sysUserInfo.setOperator((String) request.getSession().getAttribute(Constant.KEY_USER_USER_NAME));
        sysUserInfo.setOperatorIp(request.getRemoteAddr());
        sysUserServiceImpl.modifySysUserBaseInfoByUserId(sysUserInfo);
        return ReqCode.UpdateSuccess.getMessage();
    }

    @ApiOperation(notes = "会员登陆可用组",value = "会员头像上传接口")
    @PermAnno(sort = 18, group = 98)
    @PostMapping(value = "/uploadSingleHeadImage")
    public Message uploadSingleHeadImage(HttpServletRequest request) throws IOException, FileUploadException, TikaException, SAXException {
        List<Map<String,String>> resultList= new ArrayList<Map<String,String>>();
        resultList = UploadUtil.
                UploadImageAndCreateThumbNailImage(resultList, request,
                        fileSaveDirectory+FilePathEnums.headImageUploadPath.getPath(),
                        fileSavePath+FilePathEnums.headImageUploadPath.getPath(),null,null);
        if(resultList.size()<1){
            throw ReqCode.UploadError.getException();
        }
        return ReqCode.UploadSuccess.getMessage(resultList.get(0));
    }

    @ApiOperation(notes = "会员登陆可用组", value = "获取签到状态")
    @GetMapping("/getTodayCheckIn")
    @PermAnno(sort = 28, group = 98)
    public Message getTodayCheckIn() {
        Long userId = (Long) SecurityUtils.getSubject().getSession().getAttribute(Constant.USER_PRIMARY_KEY);
        return ReqCode.SelectSuccess.getMessage(sysUserServiceImpl.getTodayCheckIn(userId));
    }

    @ApiOperation(notes = "会员登陆可用组", value = "会员签到")
    @PostMapping("/memberCheckIn")
    @PermAnno(sort = 29, group = 98)
    public Message memberCheckIn() {
        Long userId = (Long) SecurityUtils.getSubject().getSession().getAttribute(Constant.USER_PRIMARY_KEY);
        sysUserServiceImpl.memberCheckIn(userId);
        return ReqCode.CheckInSuccess.getMessage();
    }

    @GetMapping(value = "/getMyAsset")
    @ApiOperation(notes = "会员登陆可用组",value = "会员获取个人资产信息")
    @PermAnno(sort = 5,group = 98)
    public Message getMyAsset(HttpServletRequest request){
        return ReqCode.SelectSuccess.getMessage(memberAssetServiceImpl.getOneByUserId((Long) request.getSession().getAttribute(Constant.USER_PRIMARY_KEY)));
    }
    @GetMapping(value = "/getAllAssetRank")
    @ApiOperation(notes = "会员登陆可用组",value = "查询积分排名")
    @PermAnno(sort = 5,group = 98)
    public Message getAllAssetRank(HttpServletRequest request,@Valid FindPagingVo findPagingVo){
        return ReqCode.SelectSuccess.getMessage(memberAssetServiceImpl.findAllRank(findPagingVo));
    }

    @GetMapping(value = "/getMyAssetRank")
    @ApiOperation(notes = "会员登陆可用组",value = "获取当前用户积分排名")
    @PermAnno(sort = 5,group = 98)
    public Message getMyAssetRank(HttpServletRequest request){
        return ReqCode.SelectSuccess.getMessage(memberAssetServiceImpl.getMyAssetRank(Integer.valueOf(request.getSession().getAttribute(Constant.USER_PRIMARY_KEY).toString())));
    }

    @ApiOperation(notes = "公开权限组", value = "公众号授权入口")
    @PostMapping(value = "/gzhlogin")
    @Transactional
    @PermAnno(sort = 2, group = 1, open = true)
    public Message gzhlogin(@RequestParam @NotBlank(message = "授权码为空") String code,
                            HttpSession httpsession,
                            HttpServletRequest request
    ) {
        //根据获取用户的openId||或者是unionid
        String openid = sysUserServiceImpl.checkOpenCodeInfo(code,request);

        CustomTypeToken customTypeToken = new CustomTypeToken(openid,"",LoginType.WXGZH,false,"");//免密登陆
        Subject subject = SecurityUtils.getSubject();
        //检测用户登陆信息
        try {
//            customTypeToken.setRememberMe(true);
            subject.login(customTypeToken);
        } catch (IncorrectCredentialsException ice) {
            // 密码错误异常
            throw ReqCode.SysLoginPasswordError.getException();
        } catch (UnknownAccountException uae) {
            // 未知用户名异常
            throw ReqCode.SysLoginUnKnowAccount.getException();
        } catch (ExcessiveAttemptsException eae) {
            // 错误登录过多的异常
            throw ReqCode.SysLoginExcessiveAttempts.getException();
        } catch (LockedAccountException lae) {
            //账号锁定异常
            throw ReqCode.SysLoginLockedAccount.getException();
        }
        //登录成功之后删除rand
        httpsession.removeAttribute(Constant.KEY_CAPTCHA);
        //创建客户端的用户信息token
        ClientToken clientToken = new ClientToken();
        BaseUser baseUser = authService.getUserByWXGZH(openid);//获取授权
        String userName = baseUser.getUserName();
        if(baseUser==null){
            throw ReqCode.UnExistingSysUser.getException();
        }

        SysUserInfoBaseVo sysUserInfoBaseVo =  sysUserServiceImpl.getUserInfoBaseVoByUserName(userName);
        //更新登陆时间
        sysUserServiceImpl.updateUserLoginTime(sysUserInfoBaseVo.getId());
        //登陆成功之后自动签到
        //生成跨域token
        String csrfToken = UUID.randomUUID().toString().replace("-", "");
        subject.getSession().setAttribute(Constant.KEY_USER_INFO, sysUserInfoBaseVo); //存储基本信息
        subject.getSession().setAttribute(Constant.KEY_USER_USER_NAME, userName); //存储基本信息
        subject.getSession().setAttribute(Constant.USER_PRIMARY_KEY, sysUserInfoBaseVo.getId());
        subject.getSession().setAttribute(Constant.KEY_CSRF_TOKEN, csrfToken);

        //插入登陆记录
        sysLoginService.saveLoinLog(request,sysUserInfoBaseVo.getId(),1);
        //生成登陆成功的返回信息
        Map<String, String> map = new HashMap<String, String>();
        map.put(Constant.KEY_CLIENT_TOKEN, ClientToken.createClientToken(clientToken));
        map.put(Constant.KEY_CSRF_TOKEN, csrfToken);
        return ReqCode.Success.getMessage(map);
    }




    @GetMapping(value = "/getWxShareConfig")
    @ApiOperation(notes = "系统公开组",value = "获取微信分享信息")
    @PermAnno(sort = 5,group = 1,open = true)
    public Message getWxShareConfig(HttpServletRequest request,@NotNull(message = "分享链接为空") String url){
        //检查一下是否jsapi-ticket是否为空
        /**
         * 1、jsapi-ticket是否为空
         * 2、jsapi-ticket_time是否过期
         * 3、access_token是否为空
         * 4、access_token_time是否过期
         * 最终拿到jsapi-ticket
         */

        if(LocalDateTime.now().isAfter(Constant.wxgzhShareTicketTime)){
            if(LocalDateTime.now().isAfter(Constant.wxgzhAccessTokenTime)){
                //获取access_token
                String token = HttpUtil.get(Constant.WXGZH_ACCESS_TOKEN_URL.replace("APPID", Constant.WXGZH_APP_ID).replace("APPSECRET", Constant.WXGZH_APP_SECRET));
//                System.out.println("获取到的access_token"+token);
                JSONObject tokenobj = JSONObject.parseObject(token);
                Constant.WXGZH_ACCESS_TOKEN = tokenobj.getString("access_token");
                Constant.wxgzhAccessTokenTime = LocalDateTime.now().plusSeconds(7000);
                //获取jsapi_ticket
                String ticket = HttpUtil.get(Constant.WXGZH_SHARE_JS_API_TICKET_URL.replace("ACCESS_TOKEN", Constant.WXGZH_ACCESS_TOKEN));
                JSONObject ticketobj = JSONObject.parseObject(ticket);
                Constant.WXGZH_SHARE_JS_API_TICKET = ticketobj.getString("ticket");
                Constant.wxgzhShareTicketTime = LocalDateTime.now().plusSeconds(7000);
            }
        }
        Map<String, String> sign = shareUtil.sign(Constant.WXGZH_SHARE_JS_API_TICKET, url);
        sign.put("appId",Constant.WXGZH_APP_ID);
        String sharaToken = ImageCaptchaUtil.generateVerifyCode(4);
        sign.put(Constant.KEY_SHARE_TOKEN,sharaToken);
        request.getSession().setAttribute(Constant.KEY_SHARE_TOKEN,sharaToken);
        return ReqCode.SelectSuccess.getMessage(sign);
    }


    @PostMapping(value = "/wxgzhShareCallBack")
    @ApiOperation(notes = "系统公开组",value = "微信公众号分享回调")
    @PermAnno(sort = 5,group = 1,open = true)
    public Message wxgzhShareCallBack(HttpServletRequest request,String shareToken,String shareType,String shareLink){
        if(request.getSession().getAttribute(Constant.USER_PRIMARY_KEY)!=null){
            if(request.getSession().getAttribute(Constant.KEY_SHARE_TOKEN)!=null&&shareToken.equals(request.getSession().getAttribute(Constant.KEY_SHARE_TOKEN).toString())){
                memberAssetServiceImpl.wxgzhShareCallBack(Long.valueOf(request.getSession().getAttribute(Constant.USER_PRIMARY_KEY).toString()));
            }
        }
        return ReqCode.OperateSuccess.getMessage();
    }

}
